package com.example.couponprovider.tcc.impl;

import com.alibaba.fastjson.JSONObject;
import com.example.couponprovider.constants.CouponStatus;
import com.example.couponprovider.domain.Coupon;
import com.example.couponprovider.domain.TccTransaction;
import com.example.couponprovider.mapper.CouponMapper;
import com.example.couponprovider.mapper.TccTransactionMapper;
import com.example.couponprovider.service.ICouponService;
import com.example.couponprovider.tcc.ICouponAction;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.example.constants.TccState;
import org.example.exception.BizException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * @author Kong
 * @date 2021-9-15 14:48
 */
@Slf4j
@Service
public class CouponAction implements ICouponAction {
    @Autowired
    private ICouponService couponService;
    @Autowired
    private TccTransactionMapper tccTransactionMapper;
    @Override
    public boolean prepareCreateOrder(BusinessActionContext businessActionContext, Coupon coupon) {
        /**
         * 一阶段Prepare
         * 1、写入Coupon，状态为初始
         * 2、写入TccTransaction，如果写入失败，说明二阶段在执行，一阶段异常，避免悬挂
         */
        String xid = RootContext.getXID();
        // 保存优惠券，状态为初始
        coupon.setState(CouponStatus.INITIAL.getValue());
        couponService.save(coupon);
        //businessActionContext.getActionContext().put("coupon",coupon);
        log.info(coupon.getId() + "");
        TccTransaction tccTransaction = new TccTransaction();
        tccTransaction.setXid(xid);
        tccTransaction.setBranchId(String.valueOf(businessActionContext.getBranchId()));
        tccTransaction.setGmtCreate(new Date());
        tccTransaction.setGmtUpdate(new Date());
        tccTransaction.setState(TccState.PREPARED.getValue());
        tccTransactionMapper.insert(tccTransaction);
        return true;
    }

    @Override
    public boolean commit(BusinessActionContext businessActionContext) {
        /**
         * 二阶段提交
         * 1、更新优惠券状态
         * 2、更新日志，注意幂等
         */
        String xid = businessActionContext.getXid();
        String branchId = String.valueOf(businessActionContext.getBranchId());
        Coupon coupon = JSONObject.parseObject(businessActionContext.getActionContext("coupon").toString(),Coupon.class);
        TccTransaction tccTransaction = tccTransactionMapper.getByXidAndBranchIdForUpdate(xid,branchId);
        if(tccTransaction == null) {
            // 抛出异常后，触发回滚
            throw new BizException("二阶段提交异常,异常原因：一阶段未执行，xid=" +xid);
        } else if(TccState.COMMITTED.getValue().equals(tccTransaction.getState())) {
            // 幂等
            return true;
        } else if(TccState.ROLLBACKED.getValue().equals(tccTransaction.getState())) {
            // 抛出异常后，触发回滚
            throw new BizException("二阶段提交异常,异常原因：已经回滚的事务不允许提交，xid=" +xid);
        }
        coupon.setState(CouponStatus.COMMITTED.getValue());
        couponService.updateById(coupon);
        tccTransactionMapper.updateStateByXidAndBranchId(TccState.COMMITTED.getValue(),xid,branchId);
        return true;
    }

    @Override
    public boolean rollback(BusinessActionContext businessActionContext) {
        /**
         * 二阶段回滚
         * 1、幂等
         * 2、空回滚
         */
        String xid = businessActionContext.getXid();
        String branchId  = String.valueOf(businessActionContext.getBranchId());
        Coupon coupon = JSONObject.parseObject(businessActionContext.getActionContext("coupon").toString(),Coupon.class);

        TccTransaction tccTransaction = tccTransactionMapper.getByXidAndBranchIdForUpdate(xid,branchId);
        if(tccTransaction == null) {
            // 说明空回滚，一阶段还未执行
            tccTransaction  = new TccTransaction();
            tccTransaction.setXid(xid);
            tccTransaction.setBranchId(branchId);
            tccTransaction.setGmtCreate(new Date());
            tccTransaction.setGmtUpdate(new Date());
            tccTransaction.setState(TccState.ROLLBACKED.getValue());
            tccTransactionMapper.insert(tccTransaction);
            return true;
        } else if(TccState.ROLLBACKED.getValue().equals(tccTransaction.getState())) {
            // 幂等
            return true;
        } else if(TccState.COMMITTED.getValue().equals(tccTransaction.getState())) {
            log.warn("已经提交的全局事务不允许回滚,xid=" + xid);
            return true;
        }
        // 删除
        couponService.removeById(coupon.getId());
        tccTransactionMapper.updateStateByXidAndBranchId(TccState.ROLLBACKED.getValue(),xid,branchId);
        return true;
    }
}
